/**
 * json 深复制
 * @param [data] 对象
 * @description cosnt a={b:{c:{d:[{e:1},{f:2}]}}}
 *              const r = cloneDeep(a)
 */
export function cloneDeep <T extends Record<string | symbol, any>>(target:T) {
	let hash = new WeakMap()
    if(typeof target !== 'object' || target === null) {
        return target
    }
    if (target instanceof RegExp) return new RegExp(target)
    if (target instanceof Date) return new Date(target)
    if (hash.has(target)) return hash.get(target)
    const cloneTarget: Array<keyof typeof Object | RegExp | Date> | object | any = Array.isArray(target) ? [] : {}
    hash.set(target, cloneTarget)
    const symKeys = Object.getOwnPropertySymbols(target)
    if (symKeys.length) {
        symKeys.forEach((sk) => {
            if (typeof target[sk] === 'object' && target[sk] !== null) {
                cloneTarget[sk] = cloneDeep(target[sk])
            } else {
                cloneTarget[sk] = target[sk]
            }
        })
    }
    for (let key of Object.keys(target)) {
        cloneTarget[key] = typeof target[key] === 'object' && target[key] !== null 
        ? cloneDeep(target[key]) : target[key]
    }  
    return cloneTarget
}
/**
 * json 取值
 * @param [data] [path] 对象，取值路径
 * @description cosnt a={b:{c:{d:[{e:1},{f:2}]}}}
 *              const r = get(a,'b.c.d.0.e')
 *              cosnt r = get(a,['b','c','d','0','e'])
 */
 export const get = <T extends Record<string, string & number & boolean & object>>(data: T, path: Array<string>|string, value = null) => {
	let current = cloneDeep(data)
	const arrayPath = Array.isArray(path) ? path : path.split('.')
	for (let item of arrayPath) {
		if(current && current[item]) {
			current = current[item]
		} else {
			return value
		}
	}
	return current || value
}
/**
 * json 赋值
 * @param [data] [path] 对象，赋值路径
 * @description cosnt a={}
 * set(a,'q.w.e.r',2)
 * a = {'q': {'w': {'e': {'r': 2}}}}
 */
export const set = <T extends Record<string, object>>(data:T, path:string, value = null) => {
	let current: object | any = data
	const arrayPath: Array<string> = Array.isArray(path) ? path : path.split('.')
	for (let p of arrayPath.slice(0,-1)) {
		if (!current[p]) current[p] = {}
		current = current[p]
	}
	let last = arrayPath[arrayPath.length-1]
	if (!current[last]) current[last] = {}
	current[last] = value
	return data
}